package com.wqj.kyee.gps.service;

import android.app.Notification;
import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.os.Binder;
import android.os.Environment;
import android.os.IBinder;
import android.util.Log;

import com.wqj.kyee.gps.bluetooth.ble.BluetoothLeService;
import com.wqj.kyee.gps.nmea.NMEA;
import com.wqj.kyee.gps.util.Constants;

import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileWriter;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;

public class NMEAParserService extends Service {

    private static  final String TAG = "NMEAParserService";

    private BluetoothLeService mBluetoothLeService;

    private String mDeviceAddress;
    private Boolean isAutoConnect;

    private Boolean mConnectedState = false;

    private File mFile;
    //private FileOutputStream mOut;
    private BufferedWriter mFileWriter;
    private final String DEFAULT_FILENAME = "_NMEA.txt";
    private FileFlushThread mThread;

    private final ServiceConnection mServiceConnection = new ServiceConnection() {

        @Override
        public void onServiceConnected(ComponentName componentName, IBinder service) {
            Log.e(TAG, "onServiceConnected");
            mBluetoothLeService = ((BluetoothLeService.LocalBinder) service).getService();
            if (!mBluetoothLeService.initialize()) {
                Log.e(TAG, "Unable to initialize Bluetooth");
                //finish();
            } else {
                // Automatically connects to the device upon successful start-up initialization.
                if ((isAutoConnect) && (!mDeviceAddress.isEmpty())) {
                    mBluetoothLeService.connect(mDeviceAddress);
                }
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            Log.e(TAG, "onServiceDisconnected");
            mBluetoothLeService = null;
        }
    };


    public NMEAParserService() {
        try {
            SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd_HH:mm:ss");
            Date curDate = new Date(System.currentTimeMillis());
            String stamp = formatter.format(curDate);
            mFile = new File(Environment.getExternalStorageDirectory(), stamp + DEFAULT_FILENAME);
            if (!mFile.exists())
                mFile.createNewFile();
//            mOut = openFileOutput(DEFAULT_FILENAME, Context.MODE_PRIVATE);
//            mFileWriter = new BufferedWriter(new OutputStreamWriter(mOut));
            mFileWriter = new BufferedWriter(new FileWriter(mFile, false));
            mThread = new FileFlushThread();
            mThread.start();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    private final IBinder mBinder = new LocalBinder();
    @Override
    public IBinder onBind(Intent intent) {
        Log.e(TAG, "onBind");

        return mBinder;
    }

    @Override
    public void onCreate() {
        Log.e(TAG, "onCreate");
        super.onCreate();

        //mDeviceAddress = ""; //= "1D:A8:95:58:08:DB";
        SharedPreferences sharedPreferences = getSharedPreferences(Constants.BTDevice_Preferences, Context.MODE_PRIVATE);
        isAutoConnect = sharedPreferences.getBoolean(Constants.SP_KEY_BT_IS_AUTO_CONNECT, false);
        //if (isAutoConnect) {
        mDeviceAddress = sharedPreferences.getString(Constants.SP_KEY_BT_DEVICE_ADRESS, "");
        //}

        Intent gattServiceIntent = new Intent(this, BluetoothLeService.class);
        bindService(gattServiceIntent, mServiceConnection, BIND_AUTO_CREATE);

        registerReceiver(mGattUpdateReceiver, makeGattUpdateIntentFilter());
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        Log.e(TAG, "onStartCommand");
        Notification.Builder builder = new Notification.Builder(this.getApplicationContext());
        Notification notification = builder.build(); // 获取构建好的Notification
        notification.defaults = Notification.DEFAULT_SOUND; //设置为默认的声音
        startForeground(Integer.MAX_VALUE, notification);

        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        Log.e(TAG, "onDestroy");
        super.onDestroy();
        mBluetoothLeService.close();
    }

    public void autoConnect() {
        Log.e(TAG, "autoConnect");
        if (!mDeviceAddress.isEmpty()) {
            if (mBluetoothLeService != null)
                mBluetoothLeService.connect(mDeviceAddress);
        }
    }

    public void connect(String deviceAddress) {
        mDeviceAddress = deviceAddress;
        if (mBluetoothLeService != null)
            mBluetoothLeService.connect(mDeviceAddress);
    }

    public void disconnect() {
        if (mBluetoothLeService != null)
            mBluetoothLeService.disconnect();
    }
    public String getDeviceAddress() {
        return mDeviceAddress;
    }

    public Boolean getConnectState() {
        return mConnectedState;
    }

    public class LocalBinder extends Binder {
        public NMEAParserService getService() {
            return NMEAParserService.this;
        }
    }

    private static IntentFilter makeGattUpdateIntentFilter() {
        final IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(BluetoothLeService.ACTION_GATT_CONNECTED);
        intentFilter.addAction(BluetoothLeService.ACTION_GATT_DISCONNECTED);
        intentFilter.addAction(BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED);
        intentFilter.addAction(BluetoothLeService.ACTION_DATA_AVAILABLE);
        intentFilter.addAction(BluetoothLeService.ACTION_WRITE_SUCCESSFUL);
        intentFilter.addAction(BluetoothLeService.ACTION_GATT_SERVICES_NO_DISCOVERED);
        intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
        return intentFilter;
    }

    String previousLine = "";
    NMEA mNMEAParser = new NMEA();
    private ArrayList<String> linesGroup = new ArrayList<>();

    private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            final String action = intent.getAction();
            if (BluetoothLeService.ACTION_GATT_CONNECTED.equals(action)) {
                Log.e(TAG, "ACTION_GATT_CONNECTED");
                mConnectedState = true;
            } else if (BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action)) {
                Log.e(TAG, "ACTION_GATT_DISCONNECTED");
                mBluetoothLeService.disconnect();
                mConnectedState = false;
            } else if (BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED.equals(action)) {
                Log.e(TAG, "ACTION_GATT_SERVICES_DISCOVERED");
            }else if (BluetoothLeService.ACTION_GATT_SERVICES_NO_DISCOVERED.equals(action)){
                Log.e(TAG, "ACTION_GATT_SERVICES_NO_DISCOVERED");
            }else if (BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action)) {
                //Log.e(TAG, "ACTION_DATA_AVAILABLE");


                byte[] data = intent.getByteArrayExtra(BluetoothLeService.EXTRA_DATA);
                ByteArrayInputStream bais = new ByteArrayInputStream(data);


                String line = previousLine;
                previousLine = "";

                while (bais.available() > 0) {
                    int tmp = bais.read();
                    line += (char) tmp;

                    if (tmp == '\n') {

                       // Log.e(TAG, line);

                        try {
                            mFileWriter.write(line);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }

                        if (line.contains(Constants.NMEA_TOKEN_GSV)) {
                            linesGroup.add(line);
                        } else {

                            if (!linesGroup.isEmpty()) {
                                ArrayList<NMEA.SVInfo> svList = mNMEAParser.parse(Constants.NMEA_TOKEN_GSV, linesGroup);
                                //Collections.sort(svList);
                                if (mInfoUpdateListener != null) {
                                    mInfoUpdateListener.onGSVUpdate(svList);
                                }
                                linesGroup.clear();
                            }

                            if (line.contains(Constants.NMEA_TOKEN_RMC)) {
                                //Log.e(TAG, "Found RMC");
                                NMEA.GPSPosition pos = mNMEAParser.parse(line);
                                if (pos != null && pos.fixed) {
                                    //Log.e(TAG, "RMC " + line);
                                    if (mInfoUpdateListener != null)
                                        mInfoUpdateListener.onRMCUpdate(pos);
                                }

                            } else if (line.contains(Constants.NMEA_TOKEN_GGA)) {
                                //Log.e(TAG, "Found GGA");
                                NMEA.GPSPosition pos = mNMEAParser.parse(line);
                                if (pos != null && pos.fixed) {
                                    //Log.e(TAG, "GGA " + line);
                                    if (mInfoUpdateListener != null)
                                        mInfoUpdateListener.onGGAUpdate(pos);
                                }
                            } else if (line.contains(Constants.NMEA_PROPRIETARY_TOKEN_AHRS)) {
                                //Log.e(TAG, "line = " + line);
                                NMEA.GPSPosition pos = mNMEAParser.parse(line);
                                if (pos != null && pos.fixed) {
                                    //Log.e(TAG, "GGA " + line);
                                    if (mInfoUpdateListener != null)
                                        mInfoUpdateListener.onAHRSUpdate(pos);
                                }
                            } else if (line.contains(Constants.NMEA_TOKEN_GSA)) {
                                Log.e(TAG, "GSA = " + line);
                            }
                        }

                        line = "";
                    }
                }

                if (!line.isEmpty()) {
                    previousLine = line;
                }

            }else if (BluetoothLeService.ACTION_WRITE_SUCCESSFUL.equals(action)) {

            } else if(BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
                int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
                switch (state) {
                    case BluetoothAdapter.STATE_TURNING_OFF:
                        Log.e(TAG, "Bluetooth turning off");
                        break;
                    case BluetoothAdapter.STATE_OFF:
                        if (mBluetoothLeService != null)
                            mBluetoothLeService.disconnect();
                        mConnectedState = false;
                        Log.e(TAG, "Bluetooth  off");
                        break;
                    case BluetoothAdapter.STATE_TURNING_ON:
                        Log.e(TAG, "Bluetooth turning on");
                        break;
                    case BluetoothAdapter.STATE_ON:
                        Log.e(TAG, "Bluetooth on");
                        break;
                    default:
                        break;
                }
            }

        }
    };

    class FileFlushThread extends Thread {
        public void run() {
            while (true) {
                try {
                    mFileWriter.flush();
                    Thread.sleep(2000);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private OnInfoUpdateListener mInfoUpdateListener;
    public void setOnInfoUpdateListener(OnInfoUpdateListener listener) {
        mInfoUpdateListener = listener;
    }

    public interface OnInfoUpdateListener {
        void onRMCUpdate(NMEA.GPSPosition position);
        void onGGAUpdate(NMEA.GPSPosition position);
        void onAHRSUpdate(NMEA.GPSPosition position);
        void onGSVUpdate(ArrayList<NMEA.SVInfo> svList);
    }
}
